package com.fit.utils.se;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.*;

/**
 * 多线程工具
 * @author hcl
 */
public class ThreadUtil {
	private static Logger log = LoggerFactory.getLogger(ThreadUtil.class);
	
	/**
	 * 初始化线程数
	 */
	private static int INIT_THREAD_NUM = 10;
	
	/**
	 * 获取一个线程池
	 * @param threadNum
	 * @return
	 */
	public static ExecutorService getThreadPool(int threadNum){
		threadNum = threadNum < 1 ? INIT_THREAD_NUM : threadNum;
		return new ThreadPoolExecutor(threadNum, threadNum * 3,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
	}
	
	/**
	 * 获取一个线程池
	 * @return
	 */
	public static ExecutorService getThreadPool(){
		return getThreadPool(-1);
	}
	
	
	/**
	 * 异步的任务执行器
	 * @param task 任务
	 * @param threadPool 线程连接池
	 */
	public static void asynTaskExecutor(Runnable task,ExecutorService threadPool){
		if(task != null){
			threadPool.execute(ThreadUtil.getRunnable(task));
		}
	}

	/**
	 * 异步的任务执行器
	 * @param task 任务
	 */
	public static void asynTaskExecutor(Runnable task){
		new Thread(ThreadUtil.getRunnable(task)).start();
	}
	
	
	/**
	 * 异步的任务执行器
	 * @param tasks 任务集合
	 * @param threadPool 线程连接池
	 */
	public static void asynTaskExecutor(List<Runnable> tasks,ExecutorService threadPool){
		for(Runnable task : tasks){
			if(task != null){
				threadPool.execute(ThreadUtil.getRunnable(task));
			}
		}
	}
	
	/**
	 * 异步的任务执行器
	 * @param tasks 任务集合
	 * @param threadNum 线程池初始化线程数量
	 */
	public static void asynTaskExecutor(List<Runnable> tasks,int threadNum){
		ExecutorService threadPool = getThreadPool(threadNum);
		asynTaskExecutor(tasks, threadPool);
		threadPool.shutdown();
	}
	
	
	/**
	 * 异步的任务执行器
	 * @param: tasks 任务集合
	 * @param: threadNum 线程池初始化线程数量
	 */
	public static void asynTaskExecutor(List<Runnable> tasks){
		asynTaskExecutor(tasks, INIT_THREAD_NUM);
	}
	
	
	
	/**
	 * 同步任务执行器(当所有任务执行完成后才会返回)
	 * @param tasks 任务集合
	 * @param threadPool 线程连接池
	 */
	public static void syncTaskExecutor(List<Runnable> tasks,ExecutorService threadPool){
		//任务执行计数器
		CountDownLatch downLatch = new CountDownLatch(tasks.size());
		for(Runnable task : tasks){
			if(task != null){
				TaskExecutor taskExecutor = new TaskExecutor(downLatch,ThreadUtil.getRunnable(task));
				threadPool.execute(taskExecutor);
			}
		}
		try {
			downLatch.await();
		} catch (InterruptedException e) {
			log.error("同步任务执行器,执行异常",e);
			throw new RuntimeException("同步任务执行器,执行异常",e);
		}
	}
	
	/**
	 * 同步任务执行器(当所有任务执行完成后才会返回)
	 * @param tasks 任务集合
	 * @param threadNum 线程池初始化线程数量
	 */
	public static void syncTaskExecutor(List<Runnable> tasks,int threadNum){
		ExecutorService threadPool = getThreadPool(threadNum);
		syncTaskExecutor(tasks, threadPool);
		threadPool.shutdown();
	}
	
	/**
	 * 同步任务执行器(当所有任务执行完成后才会返回)
	 * @param tasks
	 */
	public static void syncTaskExecutor(List<Runnable> tasks){
		syncTaskExecutor(tasks, INIT_THREAD_NUM);
	}
	


	/**
	 * @description: 同步任务执行器(当所有任务执行完成后才会返回,并且赋值返回值)
	 * @param: [tasks, threadPool]
	 * @return: void
	 * @author: hcl
	 * @date: create in 2018/11/8 23:38
	 */
	public static <T> void syncReturnTaskExecutor(List<ReturnTaskExecutor<T>> tasks,ExecutorService threadPool){
		for (ReturnTaskExecutor<T> task : tasks) {
			if(EmptyUtils.isNotEmpty(task)){
				Future<T> future = threadPool.submit(ThreadUtil.getCallable(task));
				task.setFuture(future);
			}
		}
		for (ReturnTaskExecutor<T> task : tasks) {
			task.takeResult();
		}
	}

	/**
	 * @description: 同步任务执行器(当所有任务执行完成后才会返回,并且赋值返回值)
	 * @param: [tasks, threadNum]
	 * @return: void
	 * @author: hcl
	 * @date: create in 2018/11/8 23:40
	 */
	public static <T> void syncReturnTaskExecutor(List<ReturnTaskExecutor<T>> tasks,int threadNum){
		ExecutorService threadPool = ThreadUtil.getThreadPool(threadNum);
		syncReturnTaskExecutor(tasks, threadPool);
		threadPool.shutdown();
	}

	public static <T> void syncReturnTaskExecutor(List<ReturnTaskExecutor<T>> tasks){
		syncReturnTaskExecutor(tasks, INIT_THREAD_NUM);
	}


	/**
	 * 任务执行器
	 * @author hcl
	 *
	 */
	private static class TaskExecutor implements Runnable{
		/**
		 * 任务执行计数器
		 */
		private CountDownLatch downLatch;
		
		/**
		 * 任务
		 */
		private Runnable task;
		
		/**
		 * 有参构造
		 * @param downLatch
		 * @param task
		 */
		private TaskExecutor(CountDownLatch downLatch,Runnable task) {
			this.downLatch = downLatch;
			this.task = task;
		}
		
		/**
		 * 任务执行器
		 */
		@Override
		public void run() {
			try{
				task.run();
			}finally{
				downLatch.countDown();
			}
		}
	}



	/**
	 * @description: 有返回值的任务执行器
	 * @author: hcl
	 * @date: create in 2018/11/8 23:09
	 */
	@Setter
	@Getter
	@AllArgsConstructor
	@RequiredArgsConstructor
	public static abstract class ReturnTaskExecutor<T> implements Callable<T>{

		/**
		 * @description: 执行的结果
		 * @author: hcl
		 * @date: create in 2018/11/8 23:09
		 */
		private T result;

		/**
		 * @description: 用于Callable返回结果的Future
		 * @author: hcl
		 * @date: create in 2018/11/8 23:31
		 */ 
		private Future<T> future;


		/**
		 * @description: 获取结果
		 * @param: []
		 * @return: void
		 * @author: hcl
		 * @date: create in 2018/11/8 23:35
		 */
		private void takeResult(){
			if(EmptyUtils.isNotEmpty(future)){
				try {
					result = future.get();
				} catch (Exception e) {
					log.error("线程获取结果异常！",e);
				}
			}
		}

	}



	/**
	 * @describe: 获取一个Runnable
	 * @author: hcl
	 * @date: 2018/9/27 11:12
	 * @param: [runnable]
	 * @return java.lang.Runnable
	 */
	private static Runnable getRunnable(Runnable runnable){
		return new Runnable() {
			@Override
			public void run() {
				try{
					if(runnable != null){
						runnable.run();
					}
				}catch(Exception e){
				    log.error("线程池执行异常:{}",Thread.currentThread().getName(),e);
				}
			}
		};
	}

	/**
	 * @description: 获取一个Callable
	 * @param: [callable]
	 * @return: java.util.concurrent.Callable<T>
	 * @author: hcl
	 * @date: create in 2018/11/8 23:30
	 */
	private static <T> Callable<T> getCallable(Callable<T> callable){
		return new Callable<T>() {
			@Override
			public T call() throws Exception {
				T result = null;
				try{
					if(callable != null){
						result = callable.call();
					}
				}catch(Exception e){
					log.error("线程池执行异常:{}",Thread.currentThread().getName(),e);
				}
				return result;
			}
		};
	}

}




